﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using ProcedureList.Library.Domain;
using ProcedureList.Library.Views;

namespace ProcedureList.Library.UI
{
    /// <summary>
    /// A quick search box for members in a class inspired by GExperts ProcedureList
    /// http://www.gexperts.org/tour/
    /// </summary>
    public partial class FormProcedureList : Form, IProcedureListView
    {
        private string _filterText = String.Empty;

        private IList<Domain.MethodDto> _methods;

        private MethodDto _selectedMethod;

        private Dictionary<char, Action> _keyPressStrategies;

        public FormProcedureList()
        {
            InitializeComponent();
            ActiveControl = listView1;
            _keyPressStrategies = new Dictionary<char, Action>();
            RegisterStrategies();
        }

        private void RegisterStrategies()
        {
            _keyPressStrategies.Add(Convert.ToChar(Keys.Back), FilterBackButton);
            _keyPressStrategies.Add(Convert.ToChar(Keys.Return), FilterReturnButton);
            _keyPressStrategies.Add(Convert.ToChar(Keys.Escape), () => Close());
        }

        public MethodDto SelectedMethod
        {
            get
            {
                return _selectedMethod;
            }
        }

        public void BindMethods(IList<Domain.MethodDto> methods)
        {
            _methods = methods;
            LoadClasses(methods);
            LoadMethods(methods);
        }

        void FilterMethods()
        {
            var qryFilter = _methods
                .Where(method =>
                    string.Format("{0}{1}", method.MethodName, method.ParentClassName)
                    .ToLower()
                    .Contains(_filterText.ToLower()));
            if (comboBoxClasses.SelectedIndex >= 0)
            {
                qryFilter = qryFilter.Where(method => method.ParentClassName.ToLower() == comboBoxClasses.SelectedItem.ToString().ToLower());
            }
            LoadMethods(qryFilter.ToList());
        }

        private void PerformSearch()
        {
            FilterMethods();
            FocusFirstItem();
        }

        private void FormProcedureList_KeyPress(object sender, KeyPressEventArgs e)
        {
            Action handler = null;
            if (_keyPressStrategies.TryGetValue(e.KeyChar, out handler))
            {
                handler();
            }
            else
            {

                if (!char.IsControl(e.KeyChar))
                {
                    _filterText = _filterText + e.KeyChar.ToString();
                    textBoxSearch.Text = _filterText;
                    textBoxSearch.SelectionStart = _filterText.Length;
                    PerformSearch();
                    e.Handled = true;
                }
            }
        }

        private void FilterReturnButton()
        {
            if (listView1.SelectedItems.Count > 0)
            {
                _selectedMethod = (MethodDto)listView1.SelectedItems[0].Tag;
                Close();
            }
        }

        private void FilterBackButton()
        {
            if (_filterText.Length > 0)
            {
                _filterText = _filterText.Substring(0, _filterText.Length - 1);
                textBoxSearch.Text = _filterText;
                PerformSearch();
            }
        }

        private void FocusFirstItem()
        {
            listView1.Focus();
            if (listView1.Items.Count > 0)
            {
                listView1.Items[0].Focused = true;
                listView1.Items[0].Selected = true;
            }
        }

        private void LoadClasses(IList<Domain.MethodDto> methods)
        {
            comboBoxClasses.Items.Clear();
            comboBoxClasses.Items.Add("<All>");
            comboBoxClasses.Items.AddRange(methods.GroupBy(g => g.ParentClassName)
                .Select(g => g.First().ParentClassName).ToArray());
        }

        private void LoadMethods(IList<Domain.MethodDto> methods)
        {
            listView1.BeginUpdate();
            try
            {
                listView1.Items.Clear();
                foreach (var method in methods)
                {
                    var item = listView1.Items.Add(new ListViewItem(new[]
                    {
                        string.Format ("{0}.{1}", method.ParentClassName, method.MethodName),
                        method.MethodType.ToString()
                    }));
                    item.Tag = method;
                }
            }
            finally
            {
                listView1.EndUpdate();
            }
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            _filterText = textBoxSearch.Text;
        }

        private void comboBoxClasses_SelectedIndexChanged(object sender, EventArgs e)
        {
            FilterMethods();
        }


        public Presenters.ProcedureListPresenter Presenter
        {
            get;

            set;
        }

        private void listView1_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            if (listView1.SelectedItems.Count > 0)
            {
                _selectedMethod = (MethodDto)listView1.SelectedItems[0].Tag;
                toolStripStatusLabelDeclaration.Text = _selectedMethod.Declaration;
            }
        }

        private void listView1_DoubleClick(object sender, EventArgs e)
        {
            FilterReturnButton();
        }
    }
}
